#include "events.hpp"
#include "reserva.hpp"
#include "manada.hpp"
#include "Leon.hpp"

#include <iostream>

#define YEAR 36

using namespace eosim::core;


EndViaje::EndViaje(eosim::core::Model& model): BEvent( endVL, model) {}

EndViaje::~EndViaje() {}

void EndViaje::eventRoutine(eosim::core::Entity* who)
{
	Reserva& r = (Reserva&)owner;
	Leon *l = (Leon*)who;
	// vuelve a la fila de apareamiento
	Manada *m = r.manadas[l->getManada()];
	Leon* perdedor = m->getRey();
	m->setRey(l);
	// para que este rey siga el camino que venia haciendo el leon desafiante, luego hay que 
	// meter todo esto en la logica de cuando el rey pierde
	perdedor->setManadaActual(l->getManadaActual());
	r.schedule( 0, perdedor, startVL );
	std::cout << r.getSimTime() << "\tRey perdio, nuevo rey en la manada" << m->getNumber() << " con fuerza " << l->getFuerza() << '\n';
}

StartViaje::StartViaje(eosim::core::Model& model): BEvent( startVL, model) {}

StartViaje::~StartViaje() {}

void StartViaje::eventRoutine(eosim::core::Entity* who)
{
	Reserva& r = (Reserva&)owner;
	Leon *l = (Leon*)who;
	// obtengo siguiente manada
	int manadaActual = l->getManadaActual();
	int siguienteManada = l->siguienteManada();
	Manada *m = r.manadas[siguienteManada];
	double costo = costoViaje[manadaActual][siguienteManada];

	// mando a viajar
	r.schedule(costo, l, endVL);
	std::cout << r.getSimTime() << "\tEmpezo el viaje de leon " << l->getNumber() << " de la manada " << manadaActual << " a manada " <<  siguienteManada  << "\n";
}

MaduracionLeon::MaduracionLeon(eosim::core::Model& model): BEvent(endML, model) {}

MaduracionLeon::~MaduracionLeon() {}

void MaduracionLeon::eventRoutine(eosim::core::Entity* who)
{	Reserva& r = (Reserva&)owner;

	Leon *l = (Leon*)who;
	if (l-> isMacho())
	{
		r.schedule(0, l, startVL);
		std::cout << r.getSimTime() << "\tMaduro un macho en manada " << l->getManada() << '\n';
		//schedule recorrer manadas
	}
	else
	{
		Manada *m = r.manadas[l->getManada()];
		m->toMate.push(l);
		r.schedule(0, m, startAL);
		std::cout << r.getSimTime() << "\tMaduro una hembra en manada " << m->getNumber() << '\n';
	}
}

CrianzaCachorros::CrianzaCachorros(eosim::core::Model& model): BEvent( crCL, model) {}

CrianzaCachorros::~CrianzaCachorros() {}

void CrianzaCachorros::eventRoutine(eosim::core::Entity* who)
{
	Reserva& r = (Reserva&)owner;
	Leon *l = (Leon*)who;
	Manada* m = r.manadas[l->getManada()];
	// vuelve a la fila de apareamiento
	m->toMate.push(l);
	// en caso que haya quedado vacia. Si el rey esta ocupado, ignora el llamado
	r.schedule(0, m, startAL);
	std::cout << r.getSimTime() << "\tTermino el tiempo de crianza de la leona " << l->getNumber() << " de la manada " << m->getNumber() << '\n';
}

NacimientoCamada::NacimientoCamada(eosim::core::Model& model): BEvent( evNC, model) {}

NacimientoCamada::~NacimientoCamada() {}

void NacimientoCamada::eventRoutine(eosim::core::Entity* who)
{
	Reserva& r = (Reserva&)owner;
    // por ahora, 4 luego random
	Leon *l = (Leon*)who;
	Manada* m = r.manadas[l->getManada()];
	Leon* cachorro;
	for( int i = 0; i < 3; i++)
	{
		cachorro = m->addCachorro( false );
		// tres anios de maduracion
		r.schedule( YEAR *  3, cachorro, endML );
	}
	cachorro = m->addCachorro( true );
	r.schedule( YEAR * 3, cachorro, endML );
	//chequeo si la madre muere
	l->aumentarAlumbramientos();
	if (l->getCantAlumbramientos() > 1 )
	{
		m->muereLeona(l);	
		std::cout << r.getSimTime() << "\tMurio la leona " << l->getNumber() << " de la manada " << m->getNumber() << '\n';
	}
	else
	{
		// en caso que haya quedado vacia. Si el rey esta ocupado, ignora el llamado
		r.schedule( YEAR * 2, l, crCL);
	}
	std::cout << r.getSimTime() << "\tNacieron 3 hembras y 1 macho en la camada " << m->getNumber() << '\n';
	std::cout << r.getSimTime() << "\tInicio de crianza de leona " << l->getNumber() <<  " de la manada " << m->getNumber() << '\n';

}


EndApareamiento::EndApareamiento(eosim::core::Model& model): BEvent(endAL, model) {}

EndApareamiento::~EndApareamiento() {}

void EndApareamiento::eventRoutine(eosim::core::Entity* who)
{
	Reserva& r = (Reserva&)owner;
    // por ahora 4, luego random
	Leon *l = (Leon*)who;
	Manada* m = r.manadas[l->getManada()];
	m->reyRecurso.returnBin(1);
	r.schedule( 0, m, startAL );
	// alumbramiento, 16 semanas = 112 dias
	r.schedule( 112, l, evNC );
	std::cout << r.getSimTime() << "\tFin de apareamiento  " << l->getNumber() <<  " de camada " << m->getNumber() << '\n';
}


StartApareamiento::StartApareamiento(eosim::core::Model& model): BEvent(startAL, model) {}

StartApareamiento::~StartApareamiento() {}

void StartApareamiento::eventRoutine(eosim::core::Entity* who)
{
	Reserva& r = (Reserva&)owner;
	Manada* m = (Manada*)who;

	if(!m->toMate.empty() && m->reyRecurso.isAvailable(1))
	{
		Leon *l = (Leon*)m->toMate.pop();
		m->reyRecurso.acquire(1);

		r.schedule( 3.5, l, endAL );
		std::cout << r.getSimTime() << "\tInicio de apareamiento de leona " << l->getNumber() <<  " de manada " << m->getNumber() << '\n';
	}
}

